#include <stdio.h>

/*
 * 在FPU上设置特定位
 *
 *   FPU IEEE 754
 *
 *	31 30                       23 22                            0
 *  S  |  exponent               | |  mantissa or fraction       |
 *
 *  最高数权位 MSB 位符号位。是否可能在不使用FPU指令的前提下变更浮点数的符号可呢？
 * 
 *	使用位操作C/C++指令后，不必在CPU和FPU的寄存器之间传递数据、在进行数学运算了。
 */

/* 清除MSB符号位 */
float my_abs(float i)
{
	unsigned int tmp = (*(unsigned int *) &i) &0x7FFFFFFF;
	return *(float*) &tmp;
}

/* 设置MSB符号位 */
float set_sign(float i)
{
	unsigned int tmp = (*(unsigned int*)&i) | 0x80000000;
	return *(float*)&tmp;
}

/* 求负MSB符号位 */
float negate(float i)
{
	unsigned int tmp = (*(unsigned int *)&i) ^ 0x80000000;
	return *(float*)&tmp;
}

int main()
{
	printf("my_abs():\n");
	printf("%f\n", my_abs(123.456));
	printf("%f\n", my_abs(-456.123));

	printf("set_sign():\n");
	printf("%f\n", set_sign(123.456));
	printf("%f\n", set_sign(-456.123));

	printf("negate():\n");
	printf("%f\n", negate(123.456));
	printf("%f\n", negate(-456.123));

	return 0;
}

#if 0

/*
 * intel
 */
0000000000001189 <my_abs>:
    1189:	f3 0f 1e fa          	endbr64 
    118d:	55                   	push   %rbp
    118e:	48 89 e5             	mov    %rsp,%rbp
    1191:	48 83 ec 20          	sub    $0x20,%rsp
    1195:	f3 0f 11 45 ec       	movss  %xmm0,-0x14(%rbp)	// 将一个单精度数传输到xmm寄存器的低32位
    119a:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
    11a1:	00 00 
    11a3:	48 89 45 f8          	mov    %rax,-0x8(%rbp)
    11a7:	31 c0                	xor    %eax,%eax
    11a9:	48 8d 45 ec          	lea    -0x14(%rbp),%rax
    11ad:	8b 00                	mov    (%rax),%eax
    11af:	25 ff ff ff 7f       	and    $0x7fffffff,%eax
    11b4:	89 45 f4             	mov    %eax,-0xc(%rbp)
    11b7:	48 8d 45 f4          	lea    -0xc(%rbp),%rax
    11bb:	f3 0f 10 00          	movss  (%rax),%xmm0
    11bf:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
    11c3:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
    11ca:	00 00 
    11cc:	74 05                	je     11d3 <my_abs+0x4a>
    11ce:	e8 ad fe ff ff       	callq  1080 <__stack_chk_fail@plt>
    11d3:	c9                   	leaveq 
    11d4:	c3                   	retq   

00000000000011d5 <set_sign>:
    11d5:	f3 0f 1e fa          	endbr64 
    11d9:	55                   	push   %rbp
    11da:	48 89 e5             	mov    %rsp,%rbp
    11dd:	48 83 ec 20          	sub    $0x20,%rsp
    11e1:	f3 0f 11 45 ec       	movss  %xmm0,-0x14(%rbp)
    11e6:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
    11ed:	00 00 
    11ef:	48 89 45 f8          	mov    %rax,-0x8(%rbp)
    11f3:	31 c0                	xor    %eax,%eax
    11f5:	48 8d 45 ec          	lea    -0x14(%rbp),%rax
    11f9:	8b 00                	mov    (%rax),%eax
    11fb:	0d 00 00 00 80       	or     $0x80000000,%eax
    1200:	89 45 f4             	mov    %eax,-0xc(%rbp)
    1203:	48 8d 45 f4          	lea    -0xc(%rbp),%rax
    1207:	f3 0f 10 00          	movss  (%rax),%xmm0
    120b:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
    120f:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
    1216:	00 00 
    1218:	74 05                	je     121f <set_sign+0x4a>
    121a:	e8 61 fe ff ff       	callq  1080 <__stack_chk_fail@plt>
    121f:	c9                   	leaveq 
    1220:	c3                   	retq   

0000000000001221 <negate>:
    1221:	f3 0f 1e fa          	endbr64 
    1225:	55                   	push   %rbp
    1226:	48 89 e5             	mov    %rsp,%rbp
    1229:	48 83 ec 20          	sub    $0x20,%rsp
    122d:	f3 0f 11 45 ec       	movss  %xmm0,-0x14(%rbp)
    1232:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
    1239:	00 00 
    123b:	48 89 45 f8          	mov    %rax,-0x8(%rbp)
    123f:	31 c0                	xor    %eax,%eax
    1241:	48 8d 45 ec          	lea    -0x14(%rbp),%rax
    1245:	8b 00                	mov    (%rax),%eax
    1247:	35 00 00 00 80       	xor    $0x80000000,%eax
    124c:	89 45 f4             	mov    %eax,-0xc(%rbp)
    124f:	48 8d 45 f4          	lea    -0xc(%rbp),%rax
    1253:	f3 0f 10 00          	movss  (%rax),%xmm0
    1257:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
    125b:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
    1262:	00 00 
    1264:	74 05                	je     126b <negate+0x4a>
    1266:	e8 15 fe ff ff       	callq  1080 <__stack_chk_fail@plt>
    126b:	c9                   	leaveq 
    126c:	c3                   	retq   

000000000000126d <main>:
    126d:	f3 0f 1e fa          	endbr64 
    1271:	55                   	push   %rbp
    1272:	48 89 e5             	mov    %rsp,%rbp
    1275:	48 8d 3d 88 0d 00 00 	lea    0xd88(%rip),%rdi        # 2004 <_IO_stdin_used+0x4>
    127c:	e8 ef fd ff ff       	callq  1070 <puts@plt>
    1281:	f3 0f 10 05 9f 0d 00 	movss  0xd9f(%rip),%xmm0        # 2028 <_IO_stdin_used+0x28>
    1288:	00 
    1289:	e8 fb fe ff ff       	callq  1189 <my_abs>
    128e:	f3 0f 5a c0          	cvtss2sd %xmm0,%xmm0
    1292:	48 8d 3d 75 0d 00 00 	lea    0xd75(%rip),%rdi        # 200e <_IO_stdin_used+0xe>
    1299:	b8 01 00 00 00       	mov    $0x1,%eax
    129e:	e8 ed fd ff ff       	callq  1090 <printf@plt>
    12a3:	f3 0f 10 05 81 0d 00 	movss  0xd81(%rip),%xmm0        # 202c <_IO_stdin_used+0x2c>
    12aa:	00 
    12ab:	e8 d9 fe ff ff       	callq  1189 <my_abs>
    12b0:	f3 0f 5a c0          	cvtss2sd %xmm0,%xmm0
    12b4:	48 8d 3d 53 0d 00 00 	lea    0xd53(%rip),%rdi        # 200e <_IO_stdin_used+0xe>
    12bb:	b8 01 00 00 00       	mov    $0x1,%eax
    12c0:	e8 cb fd ff ff       	callq  1090 <printf@plt>
    12c5:	48 8d 3d 46 0d 00 00 	lea    0xd46(%rip),%rdi        # 2012 <_IO_stdin_used+0x12>
    12cc:	e8 9f fd ff ff       	callq  1070 <puts@plt>
    12d1:	f3 0f 10 05 4f 0d 00 	movss  0xd4f(%rip),%xmm0        # 2028 <_IO_stdin_used+0x28>
    12d8:	00 
    12d9:	e8 f7 fe ff ff       	callq  11d5 <set_sign>
    12de:	f3 0f 5a c0          	cvtss2sd %xmm0,%xmm0
    12e2:	48 8d 3d 25 0d 00 00 	lea    0xd25(%rip),%rdi        # 200e <_IO_stdin_used+0xe>
    12e9:	b8 01 00 00 00       	mov    $0x1,%eax
    12ee:	e8 9d fd ff ff       	callq  1090 <printf@plt>
    12f3:	f3 0f 10 05 31 0d 00 	movss  0xd31(%rip),%xmm0        # 202c <_IO_stdin_used+0x2c>
    12fa:	00 
    12fb:	e8 d5 fe ff ff       	callq  11d5 <set_sign>
    1300:	f3 0f 5a c0          	cvtss2sd %xmm0,%xmm0
    1304:	48 8d 3d 03 0d 00 00 	lea    0xd03(%rip),%rdi        # 200e <_IO_stdin_used+0xe>
    130b:	b8 01 00 00 00       	mov    $0x1,%eax
    1310:	e8 7b fd ff ff       	callq  1090 <printf@plt>
    1315:	48 8d 3d 02 0d 00 00 	lea    0xd02(%rip),%rdi        # 201e <_IO_stdin_used+0x1e>
    131c:	e8 4f fd ff ff       	callq  1070 <puts@plt>
    1321:	f3 0f 10 05 ff 0c 00 	movss  0xcff(%rip),%xmm0        # 2028 <_IO_stdin_used+0x28>
    1328:	00 
    1329:	e8 f3 fe ff ff       	callq  1221 <negate>
    132e:	f3 0f 5a c0          	cvtss2sd %xmm0,%xmm0
    1332:	48 8d 3d d5 0c 00 00 	lea    0xcd5(%rip),%rdi        # 200e <_IO_stdin_used+0xe>
    1339:	b8 01 00 00 00       	mov    $0x1,%eax
    133e:	e8 4d fd ff ff       	callq  1090 <printf@plt>
    1343:	f3 0f 10 05 e1 0c 00 	movss  0xce1(%rip),%xmm0        # 202c <_IO_stdin_used+0x2c>
    134a:	00 
    134b:	e8 d1 fe ff ff       	callq  1221 <negate>
    1350:	f3 0f 5a c0          	cvtss2sd %xmm0,%xmm0
    1354:	48 8d 3d b3 0c 00 00 	lea    0xcb3(%rip),%rdi        # 200e <_IO_stdin_used+0xe>
    135b:	b8 01 00 00 00       	mov    $0x1,%eax
    1360:	e8 2b fd ff ff       	callq  1090 <printf@plt>
    1365:	b8 00 00 00 00       	mov    $0x0,%eax
    136a:	5d                   	pop    %rbp
    136b:	c3                   	retq   
    136c:	0f 1f 40 00          	nopl   0x0(%rax)

/*
 * arm
 */
00000000004005ac <my_abs>:
  4005ac:	d10083ff 	sub	sp, sp, #0x20
  4005b0:	bd000fe0 	str	s0, [sp, #12]
  4005b4:	910033e0 	add	x0, sp, #0xc
  4005b8:	b9400000 	ldr	w0, [x0]
  4005bc:	12007800 	and	w0, w0, #0x7fffffff
  4005c0:	b9001fe0 	str	w0, [sp, #28]
  4005c4:	910073e0 	add	x0, sp, #0x1c
  4005c8:	bd400000 	ldr	s0, [x0]
  4005cc:	910083ff 	add	sp, sp, #0x20
  4005d0:	d65f03c0 	ret

00000000004005d4 <set_sign>:
  4005d4:	d10083ff 	sub	sp, sp, #0x20
  4005d8:	bd000fe0 	str	s0, [sp, #12]
  4005dc:	910033e0 	add	x0, sp, #0xc
  4005e0:	b9400000 	ldr	w0, [x0]
  4005e4:	32010000 	orr	w0, w0, #0x80000000
  4005e8:	b9001fe0 	str	w0, [sp, #28]
  4005ec:	910073e0 	add	x0, sp, #0x1c
  4005f0:	bd400000 	ldr	s0, [x0]
  4005f4:	910083ff 	add	sp, sp, #0x20
  4005f8:	d65f03c0 	ret

00000000004005fc <negate>:
  4005fc:	d10083ff 	sub	sp, sp, #0x20
  400600:	bd000fe0 	str	s0, [sp, #12]
  400604:	910033e0 	add	x0, sp, #0xc
  400608:	b9400000 	ldr	w0, [x0]
  40060c:	52010000 	eor	w0, w0, #0x80000000
  400610:	b9001fe0 	str	w0, [sp, #28]
  400614:	910073e0 	add	x0, sp, #0x1c
  400618:	bd400000 	ldr	s0, [x0]
  40061c:	910083ff 	add	sp, sp, #0x20
  400620:	d65f03c0 	ret

0000000000400624 <main>:
  400624:	a9bf7bfd 	stp	x29, x30, [sp, #-16]!
  400628:	910003fd 	mov	x29, sp
  40062c:	90000000 	adrp	x0, 400000 <_init-0x428>
  400630:	911f4000 	add	x0, x0, #0x7d0
  400634:	97ffff97 	bl	400490 <puts@plt>
  400638:	529d2f20 	mov	w0, #0xe979                	// #59769
  40063c:	72a85ec0 	movk	w0, #0x42f6, lsl #16
  400640:	1e270000 	fmov	s0, w0
  400644:	97ffffda 	bl	4005ac <my_abs>
  400648:	1e22c000 	fcvt	d0, s0
  40064c:	90000000 	adrp	x0, 400000 <_init-0x428>
  400650:	911f8000 	add	x0, x0, #0x7e0
  400654:	97ffff93 	bl	4004a0 <printf@plt>
  400658:	5281f7c0 	mov	w0, #0xfbe                 	// #4030
  40065c:	72b87c80 	movk	w0, #0xc3e4, lsl #16
  400660:	1e270000 	fmov	s0, w0
  400664:	97ffffd2 	bl	4005ac <my_abs>
  400668:	1e22c000 	fcvt	d0, s0
  40066c:	90000000 	adrp	x0, 400000 <_init-0x428>
  400670:	911f8000 	add	x0, x0, #0x7e0
  400674:	97ffff8b 	bl	4004a0 <printf@plt>
  400678:	90000000 	adrp	x0, 400000 <_init-0x428>
  40067c:	911fa000 	add	x0, x0, #0x7e8
  400680:	97ffff84 	bl	400490 <puts@plt>
  400684:	529d2f20 	mov	w0, #0xe979                	// #59769
  400688:	72a85ec0 	movk	w0, #0x42f6, lsl #16
  40068c:	1e270000 	fmov	s0, w0
  400690:	97ffffd1 	bl	4005d4 <set_sign>
  400694:	1e22c000 	fcvt	d0, s0
  400698:	90000000 	adrp	x0, 400000 <_init-0x428>
  40069c:	911f8000 	add	x0, x0, #0x7e0
  4006a0:	97ffff80 	bl	4004a0 <printf@plt>
  4006a4:	5281f7c0 	mov	w0, #0xfbe                 	// #4030
  4006a8:	72b87c80 	movk	w0, #0xc3e4, lsl #16
  4006ac:	1e270000 	fmov	s0, w0
  4006b0:	97ffffc9 	bl	4005d4 <set_sign>
  4006b4:	1e22c000 	fcvt	d0, s0
  4006b8:	90000000 	adrp	x0, 400000 <_init-0x428>
  4006bc:	911f8000 	add	x0, x0, #0x7e0
  4006c0:	97ffff78 	bl	4004a0 <printf@plt>
  4006c4:	90000000 	adrp	x0, 400000 <_init-0x428>
  4006c8:	911fe000 	add	x0, x0, #0x7f8
  4006cc:	97ffff71 	bl	400490 <puts@plt>
  4006d0:	529d2f20 	mov	w0, #0xe979                	// #59769
  4006d4:	72a85ec0 	movk	w0, #0x42f6, lsl #16
  4006d8:	1e270000 	fmov	s0, w0
  4006dc:	97ffffc8 	bl	4005fc <negate>
  4006e0:	1e22c000 	fcvt	d0, s0
  4006e4:	90000000 	adrp	x0, 400000 <_init-0x428>
  4006e8:	911f8000 	add	x0, x0, #0x7e0
  4006ec:	97ffff6d 	bl	4004a0 <printf@plt>
  4006f0:	5281f7c0 	mov	w0, #0xfbe                 	// #4030
  4006f4:	72b87c80 	movk	w0, #0xc3e4, lsl #16
  4006f8:	1e270000 	fmov	s0, w0
  4006fc:	97ffffc0 	bl	4005fc <negate>
  400700:	1e22c000 	fcvt	d0, s0
  400704:	90000000 	adrp	x0, 400000 <_init-0x428>
  400708:	911f8000 	add	x0, x0, #0x7e0
  40070c:	97ffff65 	bl	4004a0 <printf@plt>
  400710:	52800000 	mov	w0, #0x0                   	// #0
  400714:	a8c17bfd 	ldp	x29, x30, [sp], #16
  400718:	d65f03c0 	ret
  40071c:	00000000 	.inst	0x00000000 ; undefined

#endif
